﻿using Newtonsoft.Json;
using rmTest.Common.CacheUtil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace rmTest.Common
{
    public static class CommonUtil
    {
        #region 对深拷贝的几个方法实现
        //利用 BinaryFormatter 实现深拷贝
        public static T DeepCopyByBinary<T>(this T obj)
        {
            T t = default(T);
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                t = (T)formatter.Deserialize(ms);
            }
            return t;
        }

        //利用 XmlSerializer 实现深拷贝
        public static T DeepCopyByXml<T>(this T obj)
        {
            T t = default(T);
            XmlSerializer xmlserialize = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                xmlserialize.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                t = (T)xmlserialize.Deserialize(ms);
            }
            return t;
        }

        //利用反射实现深拷贝
        public static T DeepCopyByReflection<T>(this T tSource)
        {
            T tResult = Activator.CreateInstance<T>();
            Type sourceType = typeof(T);
            Type resultType = typeof(T);
            var sourcePros = sourceType.GetProperties();
            foreach (var pro in sourcePros)
            {
                var sourceProValue = pro.GetValue(tSource);
                var resultPro = resultType.GetProperty(pro.Name);
                resultPro.SetValue(tResult, sourceProValue);
            }
            return tResult;
        }

        /// <summary>
        /// 序列化反序列化方式
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        public static TOut DeepCopyBySerialize<TIn, TOut>(this TIn tIn)
        {
            return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
        }

        /// <summary>
        /// 表达式目录树方式
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut DeepCopyByExpression<TIn, TOut>(this TIn tIn) //where TIn : class where TOut : class, new()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            foreach (var item in typeof(TOut).GetProperties())
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            foreach (var item in typeof(TOut).GetFields())
            {
                MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            var func = lambda.Compile();
            return func.Invoke(tIn);
        }

        /// <summary>
        /// 表达式目录树方式+泛型缓存方式
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut DeepCopyByExpressionCache<TIn, TOut>(this TIn tIn) where TIn : class where TOut : class, new()
        {
            if (FuncCache<TIn, TOut>._FUNC != null)
            {
                return FuncCache<TIn, TOut>._FUNC.Invoke(tIn);
            }
            else
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                foreach (var item in typeof(TOut).GetProperties())
                {
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                foreach (var item in typeof(TOut).GetFields())
                {
                    MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });
                FuncCache<TIn, TOut>._FUNC = lambda.Compile();
            }
            return FuncCache<TIn, TOut>._FUNC.Invoke(tIn);
            //_FUNC = lambda.Compile();//拼装是一次性的
        }
        #endregion
    }
}
